package com.suppor.rpc.provider.server;

import com.suppor.rpc.core.configuration.ConfigProperties;
import com.suppor.rpc.core.register.RegisterInfo;
import com.suppor.rpc.core.util.RpcServiceUtil;
import com.suppor.rpc.proto.codec.RpcDecoder;
import com.suppor.rpc.proto.codec.RpcEncoder;
import com.suppor.rpc.proto.handler.RpcRequestHandler;
import com.suppor.rpc.provider.annotation.RpcService;
import com.suppor.rpc.register.RegisterService;
import com.suppor.rpc.register.ZKRegisterCenter;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoop;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.ServerSocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

@Configuration
@EnableConfigurationProperties(ConfigProperties.class)
@Component
public class RpcServerInitializer implements BeanPostProcessor, InitializingBean {
    Logger LOG = LoggerFactory.getLogger(RpcServerInitializer.class);
    private int serverPort;
    private String registerType;
    private String registerAddr;
    private String serverAddr;

    @Resource
    private ConfigProperties properties;


    // 记录服务端的实例
    private ConcurrentMap<String, Object> rpcServiceMap = new ConcurrentHashMap<>();

    public RpcServerInitializer() {
        try {
            this.serverAddr = InetAddress.getLocalHost().getHostAddress();
        } catch (UnknownHostException e) {
            LOG.error("Init Rpc Server Error", e);
        }
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        this.serverPort = properties.getServerPort();
        this.registerType = properties.getRegisterType();
        this.registerAddr = properties.getRegisterAddr();
        System.out.println(serverPort);
        System.out.println(registerType);
        // 初始化完成后，启动rpcServer
        new Thread(new Runnable() {
            @Override
            public void run() {
                startRpcServer(serverPort);
            }
        },"Server-Start-Thread").start();

    }

    private void startRpcServer(int serverPort) {
        System.out.println("启动rpc server");
        EventLoopGroup boss = new NioEventLoopGroup();
        EventLoopGroup works = new NioEventLoopGroup();
        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(boss, works);
            serverBootstrap.channel(NioServerSocketChannel.class);
            serverBootstrap.option(ChannelOption.SO_BACKLOG, 1024);
            serverBootstrap.option(ChannelOption.SO_SNDBUF, 2048);
            serverBootstrap.childHandler(new ChannelInitializer<Channel>() {
                @Override
                protected void initChannel(Channel channel) throws Exception {
                    channel.pipeline().addLast(new RpcDecoder());
                    channel.pipeline().addLast(new RpcEncoder());
                    channel.pipeline().addLast(new RpcRequestHandler(rpcServiceMap));
                }
            });
            ChannelFuture future = serverBootstrap.bind(new InetSocketAddress(serverAddr, serverPort)).sync();
            LOG.info("Server {} Started On Port {}", this.serverAddr, this.serverPort);
            future.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            boss.shutdownGracefully();
            works.shutdownGracefully();
        }
    }

    // 对初始化完成的类进行扫描
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        // 扫描配置了RpcService的类
        RpcService rpcService = bean.getClass().getAnnotation(RpcService.class);
        if (null != rpcService) {
            // 完成注册
            String serviceName = rpcService.service().getName();// 服务类的全限定名
            String version = rpcService.version(); // 服务版本
            // 本地保存一份实例，工请求的时候调用
            RegisterInfo registerInfo = new RegisterInfo();
            registerInfo.setServiceName(serviceName);
            registerInfo.setVersion(version);
            registerInfo.setServerAddr(this.serverAddr);
            registerInfo.setPort(serverPort);

            // 注册到注册中心
            RegisterService registerService = new ZKRegisterCenter(properties.getRegisterAddr());
            try {
                registerService.register(registerInfo);
            } catch (Exception e) {
                LOG.error("Service {} Register Error ", serviceName);
                throw new RuntimeException(e);
            }

            String key = RpcServiceUtil.serviceKey(serviceName, version);
            rpcServiceMap.put(key, bean);
        }
        return bean;
    }

    @Bean
    public void init() throws Exception {
        System.out.println("后续一些处理");
    }
}
